﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;

namespace Hxsoft
{
	/// <summary>
	/// 字符串扩展类。
	/// </summary>
	public static partial class StringExtensions
	{
		/// <summary>
		/// 对 String 对象编码以便它们能在所有计算机上可读。
		/// </summary>
		/// <param name="str">进行编码的字符串。</param>
		/// <returns>编码后的字符串。</returns>
		public static string Escape(this string str)
		{
			if (str == null)
				return null;
			if (str == string.Empty)
				return string.Empty;

			StringBuilder strEncoded = new StringBuilder();

			char[] characters = str.ToCharArray();
			foreach (char character in characters)
			{
				int charCode = (int)character;
				if (charCode > 255)
					strEncoded.Append("%u" + charCode.ToString("X2").ToUpper());
				else
				{
					if (char.IsLetterOrDigit(character))
						strEncoded.Append(character);
					else
						strEncoded.Append("%" + charCode.ToString("X2").ToUpper());
				}
			}

			return strEncoded.ToString();
		}



		/// <summary>
		/// 解码用 escape 方法进行了编码的 String 对象。
		/// </summary>
		/// <param name="str">进行解码的字符串。</param>
		/// <returns>解码后的字符串。</returns>
		public static string Unescape(this string str)
		{
			if (str == null)
				return null;
			if (str == string.Empty)
				return string.Empty;

			StringBuilder strDecoded = new StringBuilder();

			System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex("%[0-9A-Fa-f]{2}|%u[0-9A-Fa-f]{4}");
			System.Text.RegularExpressions.MatchCollection matchs = regex.Matches(str);
			int p = 0;
			foreach (System.Text.RegularExpressions.Match match in matchs)
			{
				if (match.Index > p)
					strDecoded.Append(str.Substring(p, match.Index - p));

				string value = match.Value;
				if (value.StartsWith("%u"))
					value = value.Substring(2);
				else
					value = value.Substring(1);

				int charCode = Int32.Parse(value, System.Globalization.NumberStyles.HexNumber);
				strDecoded.Append((char)charCode);

				p += match.Length;
			}
			if (str.Length > p)
				strDecoded.Append(str.Substring(p));

			return strDecoded.ToString();
		}



		/// <summary>
		/// 取字符串的有效值（不为null和empty），如果验证字符串无效，则返回指定的默认值。
		/// </summary>
		/// <param name="value">进行验证的字符串。</param>
		/// <param name="defaultValue">当验证的字符串无效时返回的默认值。</param>
		/// <returns>获取的值。</returns>
		public static string GetEffectiveValueOrDefault(string value, string defaultValue)
		{
			if (string.IsNullOrEmpty(value))
				return defaultValue;
			return value;
		}

		/// <summary>
		/// 取字符串的有效值（不为null和empty），如果验证字符串无效，则返回指定的默认值。
		/// </summary>
		/// <param name="value">进行验证的字符串。</param>
		/// <param name="defaultValue">当验证的字符串无效时返回的默认值。</param>
		/// <returns>获取的值。</returns>
		public static string ConvertFromEffectiveValueOrDefault(object value, string defaultValue)
		{
			return GetEffectiveValueOrDefault((string)value, defaultValue);
		}



		/// <summary>
		/// 将字符串的指定前几个字符转换成小写形式。
		/// </summary>
		/// <param name="o">进行转换的字符串。</param>
		/// <param name="startsCharCount">指定的转换字符个数。</param>
		/// <returns>转换后的字符串。</returns>
		public static string StartsToLower(this string o, int startsCharCount)
		{
			return o.Substring(0, startsCharCount).ToLower() + o.Substring(startsCharCount);
		}

		/// <summary>
		/// 将字符串的指定前几个字符转换成大写形式。
		/// </summary>
		/// <param name="o">进行转换的字符串。</param>
		/// <param name="startsCharCount">指定的转换字符个数。</param>
		/// <returns>转换后的字符串。</returns>
		public static string StartsToUpper(this string o, int startsCharCount)
		{
			return o.Substring(0, startsCharCount).ToUpper() + o.Substring(startsCharCount);
		}

		/// <summary>
		/// 将字符串的指定后几个字符转换成小写形式。
		/// </summary>
		/// <param name="o">进行转换的字符串。</param>
		/// <param name="endsCharCount">指定的转换字符个数。</param>
		/// <returns>转换后的字符串。</returns>
		public static string EndsToLower(this string o, int endsCharCount)
		{
			int p = o.Length - endsCharCount;
			return o.Substring(0, p) + o.Substring(p).ToLower();
		}

		/// <summary>
		/// 将字符串的指定后几个字符转换成大写形式。
		/// </summary>
		/// <param name="o">进行转换的字符串。</param>
		/// <param name="endsCharCount">指定的转换字符个数。</param>
		/// <returns>转换后的字符串。</returns>
		public static string EndsToUpper(this string o, int endsCharCount)
		{
			int p = o.Length - endsCharCount;
			return o.Substring(0, p) + o.Substring(p).ToUpper();
		}



		/// <summary>
		/// 将字符串集合合并成为一个字符串。
		/// </summary>
		/// <param name="o">进行合并的字符串集合。</param>
		/// <param name="separator">合并集合的分隔符。</param>
		/// <returns>合并后的字符串。</returns>
		public static string Join(this ICollection<string> o, string separator)
		{
			if (o == null || o.Count <= 0) return null;
			string[] s = new string[o.Count];
			o.CopyTo(s, 0);
			return string.Join(separator, s);
		}

		/// <summary>
		/// 将字符串集合合并成为一个字符串。
		/// </summary>
		/// <param name="o">进行合并的字符串集合。</param>
		/// <param name="separator">合并集合的分隔符。</param>
		/// <returns>合并后的字符串。</returns>
		public static string Join(this ICollection<char> o, string separator)
		{
			return string.Join(separator, (from p in o select p.ToString()).ToArray());
		}



		/// <summary>
		/// 将字符串转换为客户端的 javascript 字符串。
		/// </summary>
		/// <param name="o">进行转换的字符串。</param>
		/// <returns>转换后的字符串。</returns>
		public static string ToJavascriptString(this string o)
		{
			return o.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r", "\\r").Replace("\n", "\\n").Replace("/", "\\/");
		}




		/// <summary>
		/// 从指定的字符串的开始位置移除指定的字符串的所有匹配项。
		/// </summary>
		/// <param name="source">进行操作的字符串。</param>
		/// <param name="trimString">移除的字符串。</param>
		/// <returns>移除指定字符串匹配后的字符串。</returns>
		public static string TrimStart(this string source, string trimString)
		{
			if ((!string.IsNullOrEmpty(source)) && (!string.IsNullOrEmpty(trimString)))
			{
				int p = source.IndexOf(trimString);
				while (p == 0)
				{
					source = source.Substring(trimString.Length);
					p = source.IndexOf(trimString);
				}
			}
			return source;
		}

		/// <summary>
		/// 从指定的字符串的结尾位置移除指定的字符串的所有匹配项。
		/// </summary>
		/// <param name="source">进行操作的字符串。</param>
		/// <param name="trimString">移除的字符串。</param>
		/// <returns>移除指定字符串匹配后的字符串。</returns>
		public static string TrimEnd(this string source, string trimString)
		{
			if ((!string.IsNullOrEmpty(source)) && (!string.IsNullOrEmpty(trimString)))
			{
				int p = source.LastIndexOf(trimString);
				while (p == source.Length - trimString.Length)
				{
					source = source.Substring(0, source.Length - trimString.Length);
					p = source.LastIndexOf(trimString);
				}
			}
			return source;
		}



		/// <summary>
		/// 用前后字符串将指定的字符串包装起来。
		/// </summary>
		/// <param name="source">进行包装的字符串。</param>
		/// <param name="pre">前字符串。</param>
		/// <param name="post">后字符串。</param>
		/// <returns>包装后的字符串。</returns>
		public static string Pack(this string source, string pre, string post)
		{
			if (string.IsNullOrEmpty(source)) return source;
			return pre + source + post;
		}

		/// <summary>
		/// 用字符串将指定的字符串包装起来。
		/// </summary>
		/// <param name="source">进行包装的字符串。</param>
		/// <param name="packString">包装字符串。</param>
		/// <returns>包装后的字符串。</returns>
		public static string Pack(this string source, string packString)
		{
			return Pack(source, packString, packString);
		}

		/// <summary>
		/// 去除字符串的前后包装字符串。
		/// </summary>
		/// <param name="source">进行操作的字符串。</param>
		/// <param name="pre">前字符串。</param>
		/// <param name="post">后字符串。</param>
		/// <returns>去除字符串的前后包装后的字符串。</returns>
		public static string Unpack(this string source, string pre, string post)
		{
			return TrimEnd(TrimStart(source, pre), post);
		}

		/// <summary>
		/// 去除字符串的包装字符串。
		/// </summary>
		/// <param name="source">进行操作的字符串。</param>
		/// <param name="packString">包装字符串。</param>
		/// <returns>除字符串包装后的字符串。</returns>
		public static string Unpack(this string source, string packString)
		{
			return Unpack(source, packString, packString);
		}





		/// <summary>
		/// 截取字符串。
		/// </summary>
		/// <param name="str">要截取的字符串。</param>
		/// <param name="capacity">区域所能容纳的字符长度。</param>
		/// <param name="suffix">当内容超出区域长度时的填充后缀。</param>
		/// <returns>截取的字符串。</returns>
		public static string CutString(this string str, int? capacity, string suffix)
		{
			if (string.IsNullOrEmpty(str)) return str;
			if (capacity == null) return str;
			Encoding encoding = System.Text.Encoding.GetEncoding("GB2312");
			if (encoding.GetByteCount(str) <= capacity)
				return str;

			if (!string.IsNullOrEmpty(suffix))
				capacity -= encoding.GetByteCount(suffix);

			byte[] b = encoding.GetBytes(str);
			string returnValue = encoding.GetString(b, 0, capacity.Value + 1);
			return returnValue.Substring(0, returnValue.Length - 1) + suffix;
		}

		/// <summary>
		/// 截取字符串。
		/// </summary>
		/// <param name="str">要截取的字符串。</param>
		/// <param name="len">要截取的字符串长度。</param>
		/// <returns>截取的字符串。</returns>
		public static string CutString(this string str, int? len)
		{
			return CutString(str, len, null);
		}



		/// <summary>
		/// 过滤字符串中的Html标记。
		/// </summary>
		/// <param name="str">过滤的字符串。</param>
		/// <returns>过滤掉Html标记后的字符串。</returns>
		public static string FilterHtmlTag(this string str)
		{
			if (string.IsNullOrEmpty(str)) return str;
			return RegexExtensions.ReplaceString(str, @"<[^>]*>|<\/[^>]*>", "");
		}
	}
}